# -*- coding: utf-8; Mode: Python; indent-tabs-mode: nil; tab-width: 4 -*-
#
# «usersetup» - User creation plugin.
#
# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Canonical Ltd.
#
# Authors:
#
# - Colin Watson <cjwatson@lingmo.com>
# - Evan Dandrea <ev@lingmo.com>
# - Roman Shtylman <shtylman@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import os
import re

import debconf

from lingmo-installer import i18n, misc, plugin, validation


NAME = 'usersetup'
AFTER = 'timezone'
WEIGHT = 10


def check_hostname(hostname):
    """Returns a list of reasons why the hostname is invalid."""
    errors = []
    for result in validation.check_hostname(misc.utf8(hostname)):
        if result == validation.HOSTNAME_LENGTH:
            errors.append('hostname_error_length')
        elif result == validation.HOSTNAME_BADCHAR:
            errors.append('hostname_error_badchar')
        elif result == validation.HOSTNAME_BADHYPHEN:
            errors.append('hostname_error_badhyphen')
        elif result == validation.HOSTNAME_BADDOTS:
            errors.append('hostname_error_baddots')
    return errors


def check_username(username):
    """Returns a list of reasons why the username is invalid."""
    if username:
        if not re.match('[a-z]', username[0]):
            return ['username_error_badfirstchar']
        # Technically both these conditions might hold.  However, the common
        # case seems to be that somebody starts typing their name beginning
        # with an upper-case letter, and it's probably sufficient to just
        # issue the first error in that case.
        elif not re.match('^[-a-z0-9_]+$', username):
            return ['username_error_badchar']
    return []


def make_error_string(controller, errors):
    """Returns a newline-separated string of translated error reasons."""
    return "\n".join([controller.get_string(error) for error in errors])


class PageBase(plugin.PluginUI):
    def __init__(self):
        self.suffix = misc.dmimodel()
        if self.suffix:
            self.suffix = '-%s' % self.suffix
        else:
            if misc.execute("laptop-detect"):
                self.suffix = '-laptop'
            else:
                self.suffix = '-desktop'
        self.allow_password_empty = False
        self.hostname_error_text = ""
        self.domain_connection_error_text = ""

    def set_fullname(self, value):
        """Set the user's full name."""
        raise NotImplementedError('set_fullname')

    def get_fullname(self):
        """Get the user's full name."""
        raise NotImplementedError('get_fullname')

    def set_username(self, value):
        """Set the user's Unix user name."""
        raise NotImplementedError('set_username')

    def get_username(self):
        """Get the user's Unix user name."""
        raise NotImplementedError('get_username')

    def get_password(self):
        """Get the user's password."""
        raise NotImplementedError('get_password')

    def get_verified_password(self):
        """Get the user's password confirmation."""
        raise NotImplementedError('get_verified_password')

    def set_auto_login(self, value):
        """Set whether the user should be automatically logged in."""
        raise NotImplementedError('set_auto_login')

    def get_auto_login(self):
        """Returns true if the user should be automatically logged in."""
        raise NotImplementedError('get_auto_login')

    def username_error(self, msg):
        """The selected username was bad."""
        raise NotImplementedError('username_error')

    def password_error(self, msg):
        """The selected password was bad."""
        raise NotImplementedError('password_error')

    def hostname_error(self, msg):
        """ The hostname had an error """
        raise NotImplementedError('hostname_error')

    def get_hostname(self):
        """Get the selected hostname."""
        raise NotImplementedError('get_hostname')

    def set_hostname(self, hostname):
        raise NotImplementedError('set_hostname')

    def clear_errors(self):
        pass

    def info_loop(self, *args):
        """Verify user input."""
        pass

    def set_allow_password_empty(self, empty):
        self.allow_password_empty = empty

    def plugin_translate(self, lang):
        self.hostname_error_text = i18n.get_string('hostname_error', lang)
        self.domain_connection_error_text = i18n.get_string('domain_connection_error', lang)


class PageGtk(PageBase):
    plugin_title = 'lingmo-installer/text/userinfo_heading_label'

    def __init__(self, controller, *args, **kwargs):
        from gi.repository import Gio, Gtk

        PageBase.__init__(self, *args, **kwargs)
        self.resolver = Gio.Resolver.get_default()
        self.controller = controller
        self.username_changed_id = None
        self.hostname_changed_id = None
        self.username_edited = False
        self.hostname_edited = False
        self.hostname_timeout_id = 0

        builder = Gtk.Builder()
        self.controller.add_builder(builder)
        builder.add_from_file(os.path.join(
            os.environ['LINGMO-INSTALLER_GLADE'], 'stepUserInfo.ui'))
        builder.connect_signals(self)
        self.page = builder.get_object('stepUserInfo')
        self.username = builder.get_object('username')
        self.hostname = builder.get_object('hostname')
        self.fullname = builder.get_object('fullname')
        self.password = builder.get_object('password')
        self.verified_password = builder.get_object('verified_password')
        self.login_auto = builder.get_object('login_auto')
        self.login_pass = builder.get_object('login_pass')
        self.username_error_label = builder.get_object('username_error_label')
        self.hostname_error_label = builder.get_object('hostname_error_label')
        self.password_error_label = builder.get_object('password_error_label')
        self.login_vbox = builder.get_object('login_vbox')

        self.username_ok = builder.get_object('username_ok')
        self.hostname_ok = builder.get_object('hostname_ok')
        self.fullname_ok = builder.get_object('fullname_ok')
        self.password_ok = builder.get_object('password_ok')
        self.password_strength = builder.get_object('password_strength')

        self.login_directory = builder.get_object('login_directory')
        self.login_directory_extra_label = builder.get_object('login_directory_extra_label')
        self.domain_name = builder.get_object('domain_name')
        self.domain_name_ok = builder.get_object('domain_name_ok')
        self.domain_name_error_label = builder.get_object('domain_name_error_label')
        self.domain_user = builder.get_object('domain_user')
        self.domain_user_ok = builder.get_object('domain_user_ok')
        self.domain_user_error_label = builder.get_object('domain_user_error_label')
        self.domain_passwd = builder.get_object('domain_passwd')
        self.directory_testbutton = builder.get_object('directory_testbutton')

        self.userinfo_notebook = builder.get_object('userinfo_notebook')

        # Dodgy hack to let us center the contents of the page without it
        # moving as elements appear and disappear, specifically the full name
        # okay check icon and the hostname error messages.
        paddingbox = builder.get_object('paddingbox')

        def func(box):
            box.get_parent().child_set_property(box, 'expand', False)
            box.set_size_request(box.get_allocation().width / 2, -1)

        paddingbox.connect('realize', func)

        # Some signals need to be connected by hand so that we have the
        # handler ids.
        self.username_changed_id = self.username.connect(
            'changed', self.on_username_changed)
        self.hostname_changed_id = self.hostname.connect(
            'changed', self.on_hostname_changed)

        if not os.path.exists('/usr/sbin/realm'):
            self.login_directory.hide()
            self.login_directory_extra_label.hide()
        self.login_directory_extra_label.set_sensitive(False)

        if self.controller.oem_config:
            self.fullname.set_text('OEM Configuration (temporary user)')
            self.fullname.set_editable(False)
            self.fullname.set_sensitive(False)
            self.username.set_text('oem')
            self.username.set_editable(False)
            self.username.set_sensitive(False)
            self.username_edited = True
            self.hostname.set_text('oem%s' % self.suffix)
            self.hostname_edited = True
            self.login_vbox.hide()
            # The UserSetup component takes care of preseeding passwd/user-uid.
            misc.execute_root('apt-install', 'oem-config-gtk',
                                             'oem-config-slideshow-lingmo')

        self.resolver_ok = True
        self.plugin_widgets = self.page

    # Functions called by the Page.

    def set_fullname(self, value):
        self.fullname.set_text(value)

    def get_fullname(self):
        return self.fullname.get_text()

    def set_username(self, value):
        self.username.set_text(value)

    def get_username(self):
        return self.username.get_text()

    def get_password(self):
        return self.password.get_text()

    def get_verified_password(self):
        return self.verified_password.get_text()

    def set_auto_login(self, value):
        self.login_auto.set_active(value)

    def get_auto_login(self):
        return self.login_auto.get_active()

    def username_error(self, msg):
        self.username_ok.hide()
        m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
        self.username_error_label.set_markup(m)
        self.username_error_label.show()

    def hostname_error(self, msg):
        self.hostname_ok.hide()
        m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
        self.hostname_error_label.set_markup(m)
        self.hostname_error_label.show()

    def password_error(self, msg):
        self.password_strength.hide()
        m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
        self.password_error_label.set_markup(m)
        self.password_error_label.show()

    def get_hostname(self):
        return self.hostname.get_text()

    def set_hostname(self, value):
        self.hostname.set_text(value)

    def get_login_directory(self):
        """ Use a directory for authentication """
        return self.login_directory.get_active()

    def get_domain_name(self):
        """ Get the domain name """
        return self.domain_name.get_text()

    def get_domain_user(self):
        """ Get the domain name """
        return self.domain_user.get_text()

    def get_domain_passwd(self):
        """ Get the domain name """
        return self.domain_passwd.get_text()

    def domain_name_error(self, msg):
        self.domain_name_ok.hide()
        m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
        self.domain_name_error_label.set_markup(m)
        self.domain_name_error_label.show()

    def domain_user_error(self, msg):
        self.domain_user_ok.hide()
        m = '<small><span foreground="darkred"><b>%s</b></span></small>' % msg
        self.domain_user_error_label.set_markup(m)
        self.domain_user_error_label.show()

    def clear_errors(self):
        self.username_error_label.hide()
        self.hostname_error_label.hide()
        self.password_error_label.hide()

        self.domain_name_error_label.hide()

    # Callback functions.

    def info_loop(self, widget):
        """check if all entries from Identification screen are filled. Callback
        defined in ui file."""

        if (self.username_changed_id is None or
                self.hostname_changed_id is None):
            return

        if (widget is not None and widget.get_name() == 'fullname' and
                not self.username_edited):
            self.username.handler_block(self.username_changed_id)
            new_username = misc.utf8(widget.get_text().split(' ')[0])
            new_username = new_username.encode('ascii', 'ascii_transliterate')
            new_username = new_username.decode().lower()
            new_username = re.sub('^[^a-z]+', '', new_username)
            new_username = re.sub('[^-a-z0-9_]', '', new_username)
            self.username.set_text(new_username)
            self.username.handler_unblock(self.username_changed_id)
        elif (widget is not None and widget.get_name() == 'username' and
              not self.hostname_edited):
            self.hostname.handler_block(self.hostname_changed_id)
            t = widget.get_text()
            if t:
                self.hostname.set_text(re.sub(r'\W', '', t) + self.suffix)
            self.hostname.handler_unblock(self.hostname_changed_id)

        # Do some initial validation.  We have to process all the widgets so we
        # can know if we can really show the next button.  Otherwise we'd show
        # it on any field being valid.
        complete = True

        if self.fullname.get_text():
            self.fullname_ok.show()
        else:
            self.fullname_ok.hide()

        text = self.username.get_text()
        if text:
            errors = check_username(text)
            if errors:
                self.username_error(make_error_string(self.controller, errors))
                complete = False
            else:
                self.username_ok.show()
                self.username_error_label.hide()
        else:
            self.username_ok.hide()
            self.username_error_label.hide()
            complete = False

        password_ok = validation.gtk_password_validate(
            self.controller,
            self.password,
            self.verified_password,
            self.password_ok,
            self.password_error_label,
            self.password_strength,
            self.allow_password_empty,
        )

        complete = complete and password_ok

        txt = self.hostname.get_text()
        self.hostname_ok.show()
        if txt:
            errors = check_hostname(txt)
            if errors:
                self.hostname_error(make_error_string(self.controller, errors))
                complete = False
                self.hostname_ok.hide()
            else:
                self.hostname_ok.show()
                self.hostname_error_label.hide()
        else:
            complete = False
            self.hostname_ok.hide()
            self.hostname_error_label.hide()

        self.controller.allow_go_forward(complete)

    def on_password_toggle_visibility(self, widget, icon_pos, event):
        from gi.repository import Gtk
        visibility = self.password.get_visibility()
        self.password.set_visibility(not visibility)
        self.verified_password.set_visibility(not visibility)
        self.password.set_icon_from_icon_name(
            Gtk.EntryIconPosition.SECONDARY, ('view-conceal-symbolic', 'view-reveal-symbolic')[visibility])

    def on_username_changed(self, widget):
        self.username_edited = (widget.get_text() != '')

    def on_hostname_changed(self, widget):
        self.hostname_edited = (widget.get_text() != '')

        if not self.is_automatic:
            # Let's not call this every time the user presses a key.
            from gi.repository import GLib
            if self.hostname_timeout_id:
                GLib.source_remove(self.hostname_timeout_id)
            self.hostname_timeout_id = GLib.timeout_add(
                300, self.hostname_timeout, widget)

    def lookup_result(self, resolver, result, unused):
        from gi.repository import GLib
        try:
            resolver.lookup_by_name_finish(result)
        except GLib.GError:
            pass
        else:
            self.hostname_error(self.hostname_error_text)
            self.hostname_ok.hide()

    def hostname_timeout(self, widget):
        if self.hostname_ok.get_property('visible') and self.resolver_ok:
            hostname = widget.get_text()
            for host in (hostname, '%s.local' % hostname):
                self.resolver.lookup_by_name_async(
                    host, None, self.lookup_result, None)

    def detect_bogus_result(self, hostname='xyzzy_does_not_exist'):
        # bug 760884
        # On networks where DNS fakes a response for unknown hosts,
        # don't display a warning for hostnames that already exist.
        self.resolver.lookup_by_name_async(
            hostname, None, self.bogus_lookup_result, None)

    def bogus_lookup_result(self, resolver, result, unused):
        from gi.repository import GLib
        try:
            resolver.lookup_by_name_finish(result)
        except GLib.GError:
            self.resolver_ok = True
        else:
            self.resolver_ok = False

    def validate_directory_info(self, widget=None):
        """ Validate domain information """
        domain_name_is_valid = True
        domain_info_complete = True

        domain_name_txt = self.domain_name.get_text().strip()
        domain_user_txt = self.domain_user.get_text()
        domain_passwd_txt = self.domain_passwd.get_text()

        self.domain_name_ok.hide()
        if domain_name_txt:
            errors = check_hostname(domain_name_txt)
            if errors:
                self.domain_name_error(make_error_string(self.controller, errors))
                domain_name_is_valid = False
            else:
                self.domain_name_error_label.hide()
        else:
            self.domain_name_error_label.hide()
            domain_name_is_valid = False
        self.directory_testbutton.set_sensitive(domain_name_is_valid)
        domain_info_complete = domain_name_is_valid

        if domain_user_txt:
            # Don't enforce lower case for AD administrator.
            errors = check_username(domain_user_txt.lower())
            if errors:
                self.domain_user_error(make_error_string(self.controller, errors))
                domain_info_complete = False
            else:
                self.domain_user_ok.show()
                self.domain_user_error_label.hide()
        else:
            self.domain_user_ok.hide()
            self.domain_user_error_label.hide()
            domain_info_complete = False

        if not domain_passwd_txt:
            domain_info_complete = False

        self.controller.allow_go_forward(domain_info_complete)

    def switch_userinfo_tab(self, tab):
        self.userinfo_notebook.set_current_page(tab)

        if tab == 1:
            self.title = 'lingmo-installer/text/directory_information_title'
            self.controller.allow_go_backward(True)
            self.validate_directory_info()
        else:
            self.title = self.plugin_title
            self.controller.allow_go_backward(False)
            self.controller.allow_go_forward(True)

        self.controller._wizard.set_page_title(self)

    def plugin_set_connectivity_state(self, state):
        # For AD we need network connectivity but it can be local and not
        # necessarily internet connectivity
        if not state:
            self.login_directory.set_active(False)
        self.login_directory.set_sensitive(state)

    def plugin_on_next_clicked(self):
        if self.userinfo_notebook.get_current_page() == 0 and self.get_login_directory():
            self.switch_userinfo_tab(1)
            return True
        return False

    def plugin_on_back_clicked(self):
        if self.userinfo_notebook.get_current_page() == 1:
            self.switch_userinfo_tab(0)
            return True
        return False

    def on_testdomain_click(self, widget):
        if misc.execute('realm', 'discover', self.domain_name.get_text()):
            self.domain_name_ok.show()
            self.domain_name_error_label.hide()
        else:
            self.domain_name_ok.hide()
            self.domain_name_error(self.domain_connection_error_text)
            self.domain_name_error_label.show()

    def on_login_directory_toggled(self, widget):
        self.login_directory_extra_label.set_sensitive(widget.get_active())


class PageKde(PageBase):
    plugin_breadcrumb = 'lingmo-installer/text/breadcrumb_user'

    def __init__(self, controller, *args, **kwargs):
        PageBase.__init__(self, *args, **kwargs)
        self.controller = controller

        from PyQt5 import uic
        from PyQt5.QtGui import QPixmap, QIcon

        self.plugin_widgets = uic.loadUi(
            '/usr/share/lingmo-installer/qt/stepUserSetup.ui')
        self.page = self.plugin_widgets

        self.username_edited = False
        self.hostname_edited = False

        if self.controller.oem_config:
            self.page.fullname.setText('OEM Configuration (temporary user)')
            self.page.fullname.setReadOnly(True)
            self.page.fullname.setEnabled(False)
            self.page.username.setText('oem')
            self.page.username.setReadOnly(True)
            self.page.username.setEnabled(False)
            self.page.login_pass.hide()
            self.page.login_auto.hide()
            self.username_edited = True
            self.hostname_edited = True

            self.page.hostname.setText('oem%s' % self.suffix)

            # The UserSetup component takes care of preseeding passwd/user-uid.
            misc.execute_root('apt-install', 'oem-config-kde')

        warningIcon = QPixmap(
            "/usr/share/icons/oxygen/48x48/status/dialog-warning.png")
        self.page.fullname_error_image.setPixmap(warningIcon)
        self.page.username_error_image.setPixmap(warningIcon)
        self.page.password_error_image.setPixmap(warningIcon)
        self.page.hostname_error_image.setPixmap(warningIcon)

        self.page.show_password.setIcon(QIcon.fromTheme("password-show-off"))

        self.clear_errors()

        self.page.fullname.textChanged[str].connect(self.on_fullname_changed)
        self.page.username.textChanged[str].connect(self.on_username_changed)
        self.page.hostname.textChanged[str].connect(self.on_hostname_changed)
        self.page.show_password.toggled.connect(self.on_show_password)
        # self.page.password.textChanged[str].connect(self.on_password_changed)
        # self.page.verified_password.textChanged[str].connect(
        #    self.on_verified_password_changed)

        self.page.password_debug_warning_label.setVisible(
            'LINGMO-INSTALLER_DEBUG' in os.environ)

    def on_show_password(self, state):
        from PyQt5 import QtWidgets
        from PyQt5.QtGui import QIcon

        modes = (QtWidgets.QLineEdit.Password, QtWidgets.QLineEdit.Normal)
        icons = ("password-show-off", "password-show-on")
        self.page.password.setEchoMode(modes[state])
        self.page.verified_password.setEchoMode(modes[state])
        self.page.show_password.setIcon(QIcon.fromTheme(icons[state]))

    def on_fullname_changed(self):
        # If the user did not manually enter a username create one for him.
        if not self.username_edited:
            self.page.username.blockSignals(True)
            new_username = str(self.page.fullname.text()).split(' ')[0]
            new_username = new_username.encode('ascii', 'ascii_transliterate')
            new_username = new_username.decode().lower()
            self.page.username.setText(new_username)
            self.on_username_changed()
            self.username_edited = False
            self.page.username.blockSignals(False)

    def on_username_changed(self):
        if not self.hostname_edited:
            self.page.hostname.blockSignals(True)
            self.page.hostname.setText(
                str(self.page.username.text()).strip() + self.suffix)
            self.page.hostname.blockSignals(False)

        self.username_edited = (self.page.username.text() != '')

    def on_password_changed(self):
        pass

    def on_verified_password_changed(self):
        pass

    def on_hostname_changed(self):
        self.hostname_edited = (self.page.hostname.text() != '')

    def set_fullname(self, value):
        self.page.fullname.setText(misc.utf8(value))

    def get_fullname(self):
        return str(self.page.fullname.text())

    def set_username(self, value):
        self.page.username.setText(misc.utf8(value))

    def get_username(self):
        return str(self.page.username.text())

    def get_password(self):
        return str(self.page.password.text())

    def get_verified_password(self):
        return str(self.page.verified_password.text())

    def set_auto_login(self, value):
        return self.page.login_auto.setChecked(value)

    def get_auto_login(self):
        return self.page.login_auto.isChecked()

    def username_error(self, msg):
        self.page.username_error_reason.setText(msg)
        self.page.username_error_image.show()
        self.page.username_error_reason.show()

    def password_error(self, msg):
        self.page.password_error_reason.setText(msg)
        self.page.password_error_image.show()
        self.page.password_error_reason.show()

    def hostname_error(self, msg):
        self.page.hostname_error_reason.setText(msg)
        self.page.hostname_error_image.show()
        self.page.hostname_error_reason.show()

    def get_hostname(self):
        return str(self.page.hostname.text())

    def set_hostname(self, value):
        self.page.hostname.setText(value)

    def clear_errors(self):
        self.page.fullname_error_image.hide()
        self.page.username_error_image.hide()
        self.page.password_error_image.hide()
        self.page.hostname_error_image.hide()

        self.page.username_error_reason.hide()
        self.page.password_error_reason.hide()
        self.page.hostname_error_reason.hide()


class PageDebconf(PageBase):
    plugin_title = 'lingmo-installer/text/userinfo_heading_label'

    def __init__(self, controller, *args, **kwargs):
        self.controller = controller


class PageNoninteractive(PageBase):
    def __init__(self, controller, *args, **kwargs):
        PageBase.__init__(self, *args, **kwargs)
        self.controller = controller
        self.fullname = ''
        self.username = ''
        self.password = ''
        self.verifiedpassword = ''
        self.auto_login = False
        self.encrypt_home = False
        self.console = self.controller._wizard.console

    def set_fullname(self, value):
        """Set the user's full name."""
        self.fullname = value

    def get_fullname(self):
        """Get the user's full name."""
        if self.controller.oem_config:
            return 'OEM Configuration (temporary user)'
        return self.fullname

    def set_username(self, value):
        """Set the user's Unix user name."""
        self.username = value

    def get_username(self):
        """Get the user's Unix user name."""
        if self.controller.oem_config:
            return 'oem'
        return self.username

    def get_password(self):
        """Get the user's password."""
        return self.controller.dbfilter.db.get('passwd/user-password')

    def get_verified_password(self):
        """Get the user's password confirmation."""
        return self.controller.dbfilter.db.get('passwd/user-password-again')

    def set_auto_login(self, value):
        self.auto_login = value

    def get_auto_login(self):
        return self.auto_login

    def username_error(self, msg):
        """The selected username was bad."""
        print('\nusername error: %s' % msg, file=self.console)
        self.username = input('Username: ')

    def password_error(self, msg):
        """The selected password was bad."""
        print('\nBad password: %s' % msg, file=self.console)
        import getpass
        self.password = getpass.getpass('Password: ')
        self.verifiedpassword = getpass.getpass('Password again: ')

    def set_hostname(self, name):
        pass

    def get_hostname(self):
        """Get the selected hostname."""
        # We set a default in install.py in case it isn't preseeded but when we
        # preseed, we are looking for None anyhow.
        return ''

    def clear_errors(self):
        pass


class Page(plugin.Plugin):
    def prepare(self, unfiltered=False):
        if ('LINGMO-INSTALLER_FRONTEND' not in os.environ or
                os.environ['LINGMO-INSTALLER_FRONTEND'] != 'debconf_ui'):
            self.preseed_bool('user-setup/allow-password-weak', True)
            if self.ui.get_hostname() == '':
                try:
                    seen = self.db.fget(
                        'netcfg/get_hostname', 'seen') == 'true'
                    if seen:
                        hostname = self.db.get('netcfg/get_hostname')
                        domain = self.db.get('netcfg/get_domain')
                        if hostname and domain:
                            hostname = '%s.%s' % (hostname.rstrip('.'),
                                                  domain.strip('.'))
                        if hostname != '':
                            self.ui.set_hostname(hostname)
                except debconf.DebconfError:
                    pass
            if self.ui.get_fullname() == '':
                try:
                    fullname = self.db.get('passwd/user-fullname')
                    if fullname != '':
                        self.ui.set_fullname(fullname)
                except debconf.DebconfError:
                    pass
            if self.ui.get_username() == '':
                try:
                    username = self.db.get('passwd/username')
                    if username != '':
                        self.ui.set_username(username)
                except debconf.DebconfError:
                    pass
            try:
                auto_login = self.db.get('passwd/auto-login')
                self.ui.set_auto_login(auto_login == 'true')
            except debconf.DebconfError:
                pass
        try:
            empty = self.db.get('user-setup/allow-password-empty') == 'true'
        except debconf.DebconfError:
            empty = False
        self.ui.set_allow_password_empty(empty)

        # We need to call info_loop as we switch to the page so the next button
        # gets disabled.
        self.ui.info_loop(None)

        # Trigger the bogus DNS server detection
        if (not self.is_automatic and hasattr(self.ui, 'detect_bogus_result')):
            self.ui.detect_bogus_result()

        # We intentionally don't listen to passwd/auto-login or
        # user-setup/encrypt-home because we don't want those alone to force
        # the page to be shown, if they're the only questions not preseeded.
        questions = ['^passwd/user-fullname$', '^passwd/username$',
                     '^passwd/user-password$', '^passwd/user-password-again$',
                     'ERROR']
        if 'LINGMO-INSTALLER_OEM_USER_CONFIG' in os.environ:
            command = ['/usr/lib/lingmo-installer/user-setup/user-setup-ask-oem']
            environ = {'OVERRIDE_SYSTEM_USER': '1'}
            return command, questions, environ
        else:
            # TODO: It would be neater to use a wrapper script.
            command = [
                'sh', '-c',
                '/usr/lib/lingmo-installer/user-setup/user-setup-ask /target && '
                '/usr/share/lingmo-installer/user-setup-encrypted-swap',
            ]
            return command, questions

    def set(self, question, value):
        if question == 'passwd/username':
            if self.ui.get_username() != '':
                self.ui.set_username(value)

    def run(self, priority, question):
        return plugin.Plugin.run(self, priority, question)

    def ok_handler(self):
        self.ui.clear_errors()

        fullname = self.ui.get_fullname()
        username = self.ui.get_username().strip()
        password = self.ui.get_password()
        password_confirm = self.ui.get_verified_password()
        auto_login = self.ui.get_auto_login()

        self.preseed('passwd/user-fullname', fullname)
        self.preseed('passwd/username', username)
        # TODO: maybe encrypt these first
        self.preseed('passwd/user-password', password)
        self.preseed('passwd/user-password-again', password_confirm)
        if self.ui.controller.oem_config:
            self.preseed('passwd/user-uid', '29999')
        else:
            self.preseed('passwd/user-uid', '')
        self.preseed_bool('passwd/auto-login', auto_login)
        self.preseed_bool('user-setup/encrypt-home', False)

        hostname = self.ui.get_hostname()

        # check if the hostname had errors
        errors = check_hostname(hostname)

        # showing warning message is error is set
        if errors:
            self.ui.hostname_error(
                make_error_string(self.ui.controller, errors))
            self.done = False
            self.enter_ui_loop()
            return

        if hostname is not None and hostname != '':
            hd = hostname.split('.', 1)
            self.preseed('netcfg/get_hostname', hd[0])
            if len(hd) > 1:
                self.preseed('netcfg/get_domain', hd[1])
            else:
                self.preseed('netcfg/get_domain', '')

        if hasattr(self.ui, 'get_login_directory'):
            self.preseed_bool('lingmo-installer/login_use_directory', self.ui.get_login_directory())
            if self.ui.get_login_directory():
                self.preseed('lingmo-installer/directory_domain', self.ui.get_domain_name())
                self.preseed('lingmo-installer/directory_user', self.ui.get_domain_user())
                self.preseed('lingmo-installer/directory_passwd', self.ui.get_domain_passwd())

        plugin.Plugin.ok_handler(self)

    def error(self, priority, question):
        if question.startswith('passwd/username-'):
            self.ui.username_error(self.extended_description(question))
        elif question.startswith('user-setup/password-'):
            self.ui.password_error(self.extended_description(question))
        else:
            self.ui.error_dialog(
                self.description(question),
                self.extended_description(question))
        return plugin.Plugin.error(self, priority, question)


class Install(plugin.InstallPlugin):
    def prepare(self, unfiltered=False):
        if 'LINGMO-INSTALLER_OEM_USER_CONFIG' in os.environ:
            command = ['/usr/lib/lingmo-installer/user-setup/user-setup-apply']
            environ = {'OVERRIDE_SYSTEM_USER': '1'}
        else:
            command = [
                '/usr/lib/lingmo-installer/user-setup/user-setup-apply', '/target']
            environ = {}
            if os.path.exists('/var/lib/lingmo-installer/encrypted-swap'):
                environ['OVERRIDE_ALREADY_ENCRYPTED_SWAP'] = '1'
        return command, [], environ

    def error(self, priority, question):
        self.ui.error_dialog(self.description(question),
                             self.extended_description(question))
        return plugin.InstallPlugin.error(self, priority, question)

    def install(self, target, progress, *args, **kwargs):
        progress.info('lingmo-installer/install/user')
        return plugin.InstallPlugin.install(
            self, target, progress, *args, **kwargs)
